#ifndef Mesh_h
#define Mesh_h


#include <QVector>
#include <QVector3D>
#include <QColor>
#include <QString>
#include <QVector4D>
#include <QMatrix4x4>

struct MeshMode
{
    int _ascii, _hasConf, _hasColor, _hasMask, _hasTris, _hasAlpha;
	//these numbers determine the ply IO procedure:
	//1: yes
	//0: no
	//-1: unknown, depending on the input file, used in readPly only

	MeshMode()
    { _ascii = _hasConf = _hasColor = _hasMask = _hasTris = _hasAlpha = -1; }
};

//template <class floating>
class Mesh 
{


public:
    Mesh();
    ~Mesh();

private:
    QString _name;
    MeshMode* meshMode;

//    valarray< Vertex<floating> > _verts;
    QVector<QVector3D> vertices;
    QVector<QColor> vertColors;
    QVector<QVector3D> vertNormals;
    QVector<QVector3D> faceNormals;
    QVector<int> faces;
    QVector<float> vertColorsPtr;
//	valarray< Triangle<floating> > _tris;
//	BBox3d _bbox;
	bool _hasNormals;
    QVector3D minCorner;
    QVector3D maxCorner;
    QVector3D aveVertex;

public:
    float* VerticesPointer()
    {
        return (float*)vertices.constData();
    }
    QVector<QVector3D>& VerticesList()
    {
        return vertices;
    }

    unsigned int* FacesIndicePointer()
    {
        return (unsigned int*)faces.constData();
    }
    float* VerticesColorPointer()
    {
        return (float*)vertColorsPtr.constData();
    }

    QVector<QVector3D>& VerticesNormalList()
    {
        return vertNormals;
    }

    QVector3D BoundingBoxMinCorner()
    {
        return minCorner;
    }
    QVector3D BoundingBoxMaxCorner()
    {
        return maxCorner;
    }

    //scale the vertice to [-1, 1]
    void Normalize();

    void Rotate(QMatrix4x4 rotMat);

    void ComputeNormals();

    float* VertexNormalsPointer()
    {
        return (float*)vertNormals.constData();
    }
    float* FaceNormalsPointer()
    {
        return (float*)faceNormals.constData();
    }

    QString Name() const
	{ return _name; }
	bool empty() const
	{ return NumVerts() == 0; }
	int NumVerts() const
    { return (int)vertices.size(); }
	int NumTris() const
    { return (int)faces.size()/3; }
//	BBox3d BBox() const
//	{ return _bbox; }

	bool ValidTriangleIndex(int i)
	{ return 0 <= i && i < NumTris(); }
	bool ValidVertexIndex(int i)
	{ return 0 <= i && i < NumVerts(); }

    void RemoveOccludedVertices(QMatrix4x4 modelViewMat, QMatrix4x4 projMat, QString depthImgFilename);

    void UpdateVerticesDepth(QMatrix4x4 modelViewMat, QMatrix4x4 projMat, QString depthImgFilename);

//	void Free();

    // Compute axis-aligned bounding box for whole mesh
//    void computeBBox();
	// Compute triangle and vertex normals.
//    void initNormals();
    // Compute triangle normals.
//    void computeTriNormals();
    // Compute vertex normals as average of triangle normals.
//    void computeVertNormals();
//	void FlipTriNormals();
//	void FlipVertNormals();
	
//	bool CreateFromDepthMap(const DepthMap &depth, double gap = 10);
    
    bool readPly(const char *filename, const short fileType);  // fileType 0 binary, 1 ascii
//    bool writePly(const char *filename, const MeshMode *meshMode) const;

//	static void computeTriNormals(const valarray< Vertex<floating> > &verts, valarray< Triangle<floating> > &tris);
//	static void computeVertNormals(valarray< Vertex<floating> > &verts, const valarray< Triangle<floating> > &tris);
//	static void initNormals(valarray< Vertex<floating> > &verts, valarray< Triangle<floating> > &tris);
};

#endif
